package com.gxa.pingan.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gxa.pingan.common.ExceptionCode;
import com.gxa.pingan.common.JsonResult;
import com.gxa.pingan.exception.BusinessException;
import com.gxa.pingan.listener.OrderListener;
import com.gxa.pingan.mapper.OrderMapper;
import com.gxa.pingan.pojo.*;
import com.gxa.pingan.service.OrderService;
import com.gxa.pingan.utils.CastListUtil;
import com.gxa.pingan.utils.StringUtils;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * CrossOrigin处理跨域
 * RestController:@ResponseBody ＋ @Controller
 *
 * @author YXQ
 * @date 2021/10/25 15:33
 */
@CrossOrigin
@RestController
@RequestMapping(value = "/order")
@Transactional(rollbackFor = Throwable.class)
@Api(value = "订单操作的控制器", tags = "订单操作的接口")
public class OrderController {

    @Autowired
    OrderService orderService = null;

    /**
     * 添加订单的接口方法
     *
     * @return Map
     */
    @PostMapping("/addBaseOrder")
    @ApiOperation(value = "添加订单的接口方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "map", value = "参数列表", dataType = "Order", paramType = "body")
    })
    public Map<String, Object> addBaseOrder(@RequestBody Map<String, Object> map,HttpServletRequest request) throws BusinessException, IOException {
        // 给订单实体创建uuid
        UUID uuid = UUID.randomUUID();
        // 去除uuid的"-",生成订单编号
        String uuidReplace = uuid.toString().replace("-", "");
        // 将uuid存入订单编号字段
        map.put("orderNum", uuidReplace);
        String whetherToTextOrNot1 = (String) map.get("whetherToTextOrNot");
        boolean whetherToTextOrNot = false;
        if ("1".equals(whetherToTextOrNot1)) {
            whetherToTextOrNot = true;
        }
        map.put("whetherToTextOrNot", whetherToTextOrNot);
        // 添加的具体操作
        orderService.addBaseOrder(map,request);
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("添加成功");
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 获取区域的接口方法
     *
     * @return Map
     */
    @GetMapping("/getAreaList")
    @ApiOperation(value = "获取区域的接口方法")
    public Map<String, Object> getAreaList() throws BusinessException {
        // 查询的具体操作
        List<City> areaList = orderService.getAreaList();
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("查询成功");
        jsonResult.setData(areaList);
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 获取司机的接口方法,可根据区域查询
     *
     * @param areaName 区域名
     * @return Map
     */
    @GetMapping("/getDriverList")
    @ApiOperation(value = "获取司机的接口方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "areaName", value = "区域名字", dataType = "String", paramType = "query")
    })
    public Map<String, Object> getDriverList(String areaName) throws BusinessException {
        // 查询的具体操作
        List<Driver> driverList = orderService.getDriverList(areaName);
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("查询成功");
        jsonResult.setData(driverList);
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 获取店铺的接口方法,可根据区域查询
     *
     * @param areaName 区域名
     * @return Map
     */
    @GetMapping("/getShopList")
    @ApiOperation(value = "获取店铺的接口方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "areaName", value = "areaName", dataType = "String", paramType = "query")
            , @ApiImplicitParam(name = "storesType", value = "storesType", required = true, dataType = "int", paramType = "query")
    })
    public Map<String, Object> getShopList(@RequestParam("areaName") String areaName, @RequestParam("storesType") Integer storesType) throws BusinessException {
        System.out.println(areaName + "  " + storesType);
        // 查询的具体操作
        List<Shop> shopList = orderService.getShopList(areaName, storesType);
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("查询成功");
        jsonResult.setData(shopList);
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 获取订单状态的接口方法
     *
     * @return Map
     */
    @GetMapping("/getOrderTypeList")
    @ApiOperation(value = "获取订单状态的接口方法")
    public Map<String, Object> getOrderTypeList() throws BusinessException {
        // 查询的具体操作
        List<Message> orderTypeList = orderService.getOrderTypeList();
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("查询成功");
        jsonResult.setData(orderTypeList);
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 获取订单类型的接口方法
     *
     * @return Map
     */
    @GetMapping("/getTypeList")
    @ApiOperation(value = "获取订单类型的接口方法")
    public Map<String, Object> getTypeList() throws BusinessException {
        // 查询的具体操作
        List<Message> orderTypeList = orderService.getTypeList();
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("查询成功");
        jsonResult.setData(orderTypeList);
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 获取订单状态的接口方法
     *
     * @return Map
     */
    @GetMapping("/getOrderSourceList")
    @ApiOperation(value = "获取订单来源的接口方法")
    public Map<String, Object> getOrderSourceList() throws BusinessException {
        // 查询的具体操作
        List<Message> orderSourceList = orderService.getOrderSourceList();
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("查询成功");
        jsonResult.setData(orderSourceList);
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 根据条件,分页,以及模糊查询得到订单的列表的接口方法
     *
     * @param map 参数列表
     * @return 订单的集合
     */
    @PostMapping("/getOrderList")
    @ApiOperation(value = "根据条件查询得到订单的列表的接口方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "map", value = "参数列表", paramType = "body")
    })
    public Map<String, Object> getOrderList(@RequestBody Map<String, Object> map) throws BusinessException {
        // 调用查询的核心操作
        List<Order> orderList = orderService.getOrderList(map);
        // 全查询获取总的记录数
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("查询成功");
        // 准备一个获取count的集合
        map.put("size",0);
        List<Order> orderList1 = orderService.getOrderAllList(map);
        // 获取集合的大小-返回给前端作为count
        int size = orderList1.size();
        jsonResult.put("count", size);
        //------------------------
        jsonResult.setData(orderList);
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 获取还车订单列表的接口方法
     * 列表显示所有未添加还车订单的订单。或者在查询的订单列表里显示所查询的未还车的订单
     *
     * @return Map
     */
    @GetMapping("/getReturnCarList")
    @ApiOperation(value = "获取还车订单列表的接口方法")
    public Map<String, Object> getReturnCarList() throws BusinessException {
        // 查询的具体操作
        List<OrderVo> returnCarList = orderService.getReturnCarList();
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("查询成功");
        jsonResult.setData(returnCarList);
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 获取还车订单列表的接口方法
     * 列表显示所有未添加还车订单的订单。或者在查询的订单列表里显示所查询的未还车的订单
     *
     * @return Map
     */
    @PostMapping("/exportReturnCarList")
    @ApiOperation(value = "导出还车订单列表的接口方法")
    public ResponseEntity<byte[]> exportReturnCarList() throws BusinessException, UnsupportedEncodingException {
        // 查询的具体操作
        List<OrderVo> returnCarList = orderService.getReturnCarList();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        // 语雀的核心写操作
        EasyExcel.write(outputStream, OrderVo.class).sheet("还车订单信息表").doWrite(returnCarList);
        // 缓冲数组
        byte[] bytes = outputStream.toByteArray();
        // 获取请求头信息
        HttpHeaders httpHeaders = new HttpHeaders();
        // 设置请求头,告诉浏览器，以附件方式打开，而不是在页面上浏览
        httpHeaders.setContentDispositionFormData("attachment", URLEncoder.encode("还车订单信息表.xlsx", "utf-8"));
        return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK);
    }

    /**
     * 导出订单的接口方法
     * 用户可通过列表第一列的选择按钮选择需要导出的内容
     * 导出的数据表格中要加上用户选择的修理部位和价格的信息
     *
     * @param exportList 待导出内容的id的数组
     * @throws IOException 异常
     */
    @PostMapping("/exportOrderList")
    @ApiOperation(value = "导出订单的接口方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "exportList", value = "参数列表", dataType = "List", paramType = "body")
    })
    public void exportOrderList(@RequestBody Map<String, Object> exportList, HttpServletResponse response) throws IOException, BusinessException {
        Object object = exportList.get("exportList");
        List<Integer> idList = CastListUtil.castList(object, Integer.class);

        // 如果前端没有选择就给一个空数据返回-
        List<OrderVo> lists = new ArrayList<>();
        // 判断前端的id数组是否为空
        if (idList.size() != 0) {
            // 查询到需要导出的集合
            lists = orderService.exportBatchOrderList(idList);
        }
        // 声明输出流对象
        ServletOutputStream out = null;
        // 编辑生成表格文件的文件名
        String excelName = "选中订单导出-" + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())) + ".xlsx";
        // 设置请求头信息,告诉前端以附件形式下载
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(excelName, "utf-8"));
        // 接收输出流对象
        out = response.getOutputStream();
        // 调用语雀的写表格方法
        EasyExcelFactory.write(out, OrderVo.class).
                registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("选中订单的导出表").doWrite(lists);
        if (out != null) {
            out.close();
        }
    }

    /**
     * 导出第三方订单的接口方法
     * 用户可通过列表第一列的选择按钮选择需要导出的内容
     * 导出的数据表格中要加上用户选择的修理部位和价格的信息--VO对象解决
     *
     * @throws IOException 异常
     */
    @GetMapping("/exportThreeOrderList")
    @ApiOperation(value = "导出第三方订单的接口方法")
    public void exportThreeOrderList(HttpServletResponse response) throws IOException, BusinessException {
        // 查询到需要导出的集合
        List<OrderVo> lists = orderService.getThreeOrderList();
        // 声明输出流对象
        ServletOutputStream out = null;
        // 编辑生成表格文件的文件名
        String excelName = "第三方订单导出-" + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())) + ".xlsx";
        // 设置请求头信息,告诉前端以附件形式下载
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(excelName, "utf-8"));
        // 接收输出流对象
        out = response.getOutputStream();
        // 调用语雀的写表格方法
        EasyExcelFactory.write(out, OrderVo.class).
                registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("第三方订单表").doWrite(lists);
        if (out != null) {
            out.close();
        }
    }

    /**
     * 导入订单的接口方法
     *
     * @return Map map
     * @throws IOException 异常
     */
    @PostMapping("/importOrderList")
    @ApiOperation(value = "导入订单的接口方法")
    public Map<String, Object> importOrderList(@RequestParam("file") MultipartFile multipartFile, HttpServletRequest request) throws BusinessException {
        // 1.---------上传文件----
        String originalFilename = multipartFile.getOriginalFilename();
        // 从原始文件名中获取后缀,作为新添加的文件的文件名后缀(匹配)
        String suffix = originalFilename.substring(originalFilename.indexOf(".") + 1);
        // 使用UUID作为文件名,保证服务器中存放的文件名唯一
        String targetFile = UUID.randomUUID().toString().replace("-", "") + "." + suffix;
        // 通过request获取当前程序的根路径"/"
        String path = request.getServletContext().getRealPath("/");
        String fileName = path + "/excel/" + targetFile;
        // 构建文件对象
        File uploadFile = new File(fileName);
        // 核心操作(含有异常操作, 利用异常设定状态码(和前端约定)
        try {
            multipartFile.transferTo(uploadFile);
        } catch (IOException e) {
            // 当异常发生时抛出自定义异常信息,传递给前端
            throw new BusinessException(ExceptionCode.UPLOAD_FALSE);
        }
        // --- 导入表格
        // 定义一个监听器对象,后面获取集合用
        OrderListener orderListener = new OrderListener();
        // 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(fileName, OrderVo.class, orderListener).sheet().doRead();
        // 获取集合返回给前端渲染
        List<OrderVo> list = orderListener.getList();
        // 将读取到的订单信息储存到数据库
        for (OrderVo orderVo : list) {
            orderService.addImportOrder(orderVo);
        }
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("导入成功");
        jsonResult.setData(list);
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 删除订单的接口方法
     *
     * @param deleteIds 待删除订单的id数组
     * @return Map map
     * @throws IOException 异常
     */
    @PostMapping("/deleteOrderList")
    @ApiOperation(value = "删除订单的接口方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "deleteIds", value = "参数列表", dataType = "List", paramType = "body")
    })
    public Map<String, Object> deleteOrderList(@RequestBody Map<String, Object> deleteIds) throws IOException, BusinessException {
        System.out.println(deleteIds);
        Object object = deleteIds.get("deleteIds");
        List<Integer> idList = CastListUtil.castList(object, Integer.class);
        System.out.println(idList);
        // 删除的具体操作
        orderService.deleteBatchOrder(idList);
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("删除成功");
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 获取订单详细信息的接口方法
     *
     * @param orderNum 订单编号
     * @return Map map
     */
    @PostMapping("/getAll")
    @ApiOperation(value = "根据订单编号获取订单详细信息(详情)的接口方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderNum", value = "订单编号", dataType = "String", paramType = "query")
    })
    public Map<String, Object> getAll(String orderNum){
        System.out.println("----orderNum"+orderNum);
        // 查询的具体操作
        Order orderAll = orderService.getOrderAll(orderNum);

        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("查询成功");
        jsonResult.setData(orderAll);
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

    /**
     * 获取订单详细信息的接口方法
     *
     * @param phone 订单编号
     * @return Map map
     */
    @PostMapping("/checkPhone")
    @ApiOperation(value = "判断手机号是否正确的接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query")
    })
    public Map<String, Object> checkPhone(String phone) throws BusinessException {
        // 判断操作
        if (!StringUtils.isEmpty(phone)){
            // 通过正则表达式
            if (!StringUtils.isPhoneNumber(phone)){
                throw new BusinessException(ExceptionCode.PHONE_ERROR);
            }
        }
        // 生成json的结果集传给前端
        JsonResult jsonResult = new JsonResult();
        // 给json结果集赋值
        jsonResult.setCode("1");
        jsonResult.setMsg("手机号输入正确");
        // 通过return返回给前端
        return jsonResult.getDataMap();
    }

}
